﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LotteryVote.Entity;
using LotteryVote.Utility;
using System.Web;
using System.Web.Caching;
using LotteryVote.Data;

namespace LotteryVote.Logic.Limit
{
    public class LimitContext
    {
        private const string M_DBUPPERLIMITKEY = "DBUPPERLIMIT";
        private const string M_CACHEUPPERLIMITKEY = "CACHEUPPERLIMIT";

        private static object _lockHelper = new object();
        private static LimitContext _context;
        private LimitContext() { }

        private BetUpperLimitFacade _blUpperLimit;
        public BetUpperLimitFacade BlUpperLimit
        {
            get
            {
                if (_blUpperLimit == null)
                    _blUpperLimit = new BetUpperLimitFacade();
                return _blUpperLimit;
            }
            set
            {
                _blUpperLimit = value;
            }
        }

        public static LimitContext Instance
        {
            get
            {
                if (_context == null)
                {
                    lock (_lockHelper)
                    {
                        if (_context == null)
                            _context = new LimitContext();
                    }
                }
                return _context;
            }
        }

        /// <summary>
        /// 数据库投注上限（保持与数据库同步）.
        /// </summary>
        public IList<BetUpperLimit> DBUpperLimitList
        {
            get
            {
                var limitList = HttpContext.Current.Cache[M_DBUPPERLIMITKEY] as IList<BetUpperLimit>;
                if (limitList == null)
                {
                    limitList = BlUpperLimit.ListTodayUpperLimit();
                    //两小时没操作则删除缓存
                    HttpContext.Current.Cache.Add(M_DBUPPERLIMITKEY, limitList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), CacheItemPriority.Normal, null);
                }
                return limitList;
            }
            private set
            {
                HttpContext.Current.Cache[M_DBUPPERLIMITKEY] = value;
            }
        }
        /// <summary>
        /// 投注上限缓存.
        /// </summary>
        public IList<BetUpperLimit> CacheUpperLimitList
        {
            get
            {
                var limitList = HttpContext.Current.Cache[M_CACHEUPPERLIMITKEY] as IList<BetUpperLimit>;
                if (limitList == null)
                {
                    limitList = BlUpperLimit.ListTodayUpperLimit();
                    //两小时没操作则删除缓存
                    HttpContext.Current.Cache.Add(M_CACHEUPPERLIMITKEY, limitList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), CacheItemPriority.Normal, null);
                }
                return limitList;
            }
            set
            {
                HttpContext.Current.Cache[M_CACHEUPPERLIMITKEY] = value;
            }
        }
        public BetUpperLimit GetUpperLimit(int limitId)
        {
            var limit = LimitContext.Instance.CacheUpperLimitList.Find(it => it.LimitId == limitId);
            if (limit == null)
            {
                limit = BlUpperLimit.DaUpperLimit.GetUpperLimit(limitId);
                DBUpperLimitList.Add(limit);
                CacheUpperLimitList.Add(limit);
            }
            return limit;
        }
        /// <summary>
        ///更新指定限制.
        /// </summary>
        /// <param name="limitId">The limit id.</param>
        public void UpdateUpperLimit(int limitId)
        {
            var cacheLimit = CacheUpperLimitList.Find(it => it.LimitId == limitId);
            var dbLimit = DBUpperLimitList.Find(it => it.LimitId == limitId);
            var limit = BlUpperLimit.DaUpperLimit.GetUpperLimit(limitId);
            if (cacheLimit != null)
                CacheUpperLimitList.Remove(cacheLimit);
            if (dbLimit != null)
                DBUpperLimitList.Remove(dbLimit);

            CacheUpperLimitList.Add(limit);
            DBUpperLimitList.Add(limit);
        }

        /// <summary>
        /// 将缓存上限限制同步到数据库当中.
        /// </summary>
        /// <param name="tandemDA">如果存在事务串联，则传入要串联的DA，否则传入null.</param>
        public void UpdateCacheUpperLimitToDB(DataBase tandemDA = null)
        {
            if (tandemDA != null)
                BlUpperLimit.DaUpperLimit.Tandem(tandemDA);
            lock (_lockHelper)
            {
                try
                {
                    var updateLimits = GetUpdatedUpperLimit();
                    updateLimits.ForEach(it =>
                    {
                        BlUpperLimit.DaUpperLimit.Update(it);
                    });
                    CloneTo(CacheUpperLimitList, DBUpperLimitList);
                }
                catch
                {
                    CloneTo(DBUpperLimitList, CacheUpperLimitList);
                    throw;
                }
            }
        }
        /// <summary>
        ///将一条上限限制规则更新到数据同步集中.
        /// </summary>
        /// <param name="limit">The limit.</param>
        public void UpdateUpperLimitToDB(BetUpperLimit limit)
        {
            var cacheLimit = DBUpperLimitList.Find(it => it.LimitId == limit.LimitId);
            if (cacheLimit != null)
                DBUpperLimitList.Remove(cacheLimit);
            DBUpperLimitList.Add(limit);
        }
        /// <summary>
        /// 获取已更改的上限限制.
        /// </summary>
        /// <returns></returns>
        private IList<BetUpperLimit> GetUpdatedUpperLimit()
        {
            List<BetUpperLimit> limitList = new List<BetUpperLimit>();
            LimitContext.Instance.CacheUpperLimitList.ForEach(it =>
            {
                var limit = LimitContext.Instance.DBUpperLimitList.Find(x => x.LimitId == it.LimitId);
                if (limit == null ||
                    it.NextLimit != limit.NextLimit ||
                    it.UpperLlimit != limit.UpperLlimit ||
                    it.TotalBetAmount != limit.TotalBetAmount ||
                    it.DropValue != limit.DropValue)
                    limitList.Add(it);
            });
            return limitList;
        }
        private void CloneTo(IList<BetUpperLimit> source, IList<BetUpperLimit> target)
        {
            target.Clear();
            List<BetUpperLimit> list = new List<BetUpperLimit>();
            foreach (var item in source)
            {
                var limit = item.Clone() as BetUpperLimit;
                target.Add(limit);
            }
        }

    }
}
